package rpc;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * InvocationHandler 接口的实现类 <br>
 * Client端代理对象的方法调用都会被 Invoker 的 invoke() 方法捕获
 * 
 * @author 宋挺
 */
public class Invoker implements InvocationHandler {
	/** RPC协议接口的 Class对象 */
	private Class<?> intface;
	/** Client 端 Socket */
	private Socket client;
	/** 用于向 Server端发送 RPC请求的输出流 */
	private ObjectOutputStream oos;
	/** 用于接收 Server端返回的 RPC请求结果的输入流 */
	private ObjectInputStream ois;

	/**
	 * 构造一个 Socket实例 client, 并连接到指定的 Server端地址, 端口
	 * 
	 * @param intface
	 *            RPC协议接口的 Class对象
	 * @param serverAdd
	 *            Server端地址
	 * @param serverPort
	 *            Server端监听的端口
	 */
	public Invoker(Class<?> intface, String serverAdd, int serverPort) throws UnknownHostException, IOException {
		this.intface = intface;
		client = new Socket(serverAdd, serverPort);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		try {
			// 封装 RPC请求
			Invocation invocation = new Invocation(intface, method.getName(), method.getParameterTypes(), args);
			// 打开 client 的输出流
			oos = new ObjectOutputStream(client.getOutputStream());
			// 序列化, 将 RPC请求写入到 client 的输出流中
			oos.writeObject(invocation);
			oos.flush();

			// 等待 Server端返回 RPC请求结果 //

			// 打开 client 的输入流
			ois = new ObjectInputStream(client.getInputStream());
			// 反序列化, 从输入流中读取 RPC请求结果
			Object res = ois.readObject();
			// 向 client 返回 RPC请求结果
			return res;
		} finally { // 关闭资源
			CloseUtil.closeAll(ois, oos);
			CloseUtil.closeAll(client);
		}
	}
}
